package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.DeviceLocationTypeEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceDataMapper;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliyunIotProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.DeviceDataGraphVo;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class DeviceServiceImpl implements DeviceService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private Client client;

    @Autowired
    private AliyunIotProperties aliyunIotProperties;

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private DeviceDataMapper deviceDataMapper;

    @Override
    public void syncProductList() {
        QueryProductListRequest request = new QueryProductListRequest();
        request.setCurrentPage(1).setPageSize(20).setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        QueryProductListResponse queryProductListResponse = null;
        try {
            queryProductListResponse = client.queryProductList(request);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        QueryProductListResponseBody.QueryProductListResponseBodyDataList list = queryProductListResponse.getBody().getData().getList();

        List<ProductVo> collect = list.getProductInfo().stream().map(productInfo -> {
            ProductVo productVo = new ProductVo();
            productVo.setProductName(productInfo.getProductName());
            productVo.setProductKey(productInfo.getProductKey());
            return productVo;
        }).collect(Collectors.toList());
        redisTemplate.opsForValue().set(CacheConstants.IOT_ALL_PRODUCT, JSONUtil.toJsonStr(collect));
    }

    @Override
    public List<ProductVo> allProduct() {
        //1. 从redis中获取产品数据列表
        String productList = redisTemplate.opsForValue().get(CacheConstants.IOT_ALL_PRODUCT);
        if (StrUtil.isEmpty(productList)) {
            return Collections.emptyList();
        }
        //2. 数据转化封装
        return JSONUtil.toList(productList, ProductVo.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void registerDevice(DeviceDto deviceDto) {
        //1. 判断设备名称是否重复
        Integer count = deviceMapper.selectDeviceByName(deviceDto.getDeviceName());
        if (count > 0){
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }
        //2. 注册设备到物联网平台
        RegisterDeviceRequest registerDeviceRequest = deviceDto.getRegisterDeviceRequest();
        registerDeviceRequest.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        RegisterDeviceResponse registerDeviceResponse;
        try {
            registerDeviceResponse = client.registerDevice(registerDeviceRequest);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        if (registerDeviceResponse == null || !registerDeviceResponse.getBody().getSuccess()){
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //3. 保存设备信息到本地数据库
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        device.setIotId(registerDeviceResponse.getBody().getData().getIotId());
        QueryProductRequest queryProductRequest = new QueryProductRequest();
        queryProductRequest.setProductKey(deviceDto.getProductKey());
        queryProductRequest.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        QueryProductResponse queryProductResponse = null;
        try {
            queryProductResponse = client.queryProduct(queryProductRequest);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }
        if (queryProductResponse == null || !queryProductResponse.getBody().getSuccess()){
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }
        String productName = queryProductResponse.getBody().getData().getProductName();
        device.setProductName(productName);
        device.setHaveEntranceGuard(productName.contains("门禁")? 1 : 0);
        //如果是随身设备.设置物理位置为-1
        if (Objects.equals(deviceDto.getLocationType(), DeviceLocationTypeEnum.FIXED_DEVICE)){
            device.setPhysicalLocationType(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal());
        }
        try {
            deviceMapper.insert(device);
        }catch (Exception e){
            e.printStackTrace();
            //如果出现异常删除物联网平台注册的设备
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setIotId(device.getIotId());
            deleteDeviceRequest.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
            try {
                client.deleteDevice(deleteDeviceRequest);
            }catch (Exception ex){
                ex.printStackTrace();
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
    }

    @Override
    public PageResponse<DeviceVo> pageQueryDevice(DevicePageQueryDto devicePageQueryDto) {
        PageHelper.startPage(devicePageQueryDto.getPageNum(), devicePageQueryDto.getPageSize());
        Page<DeviceVo> page = deviceMapper.pageQueryDevice(devicePageQueryDto);
        return PageResponse.of(page, DeviceVo.class);
    }

    @Override
    public DeviceVo queryDeviceDetail(DeviceDto deviceDto) {
        QueryDeviceDetailRequest queryDeviceDetailRequest = new QueryDeviceDetailRequest();
        queryDeviceDetailRequest.setIotId(deviceDto.getIotId());
        queryDeviceDetailRequest.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        QueryDeviceDetailResponse queryDeviceDetailResponse;
        try {
            queryDeviceDetailResponse = client.queryDeviceDetail(queryDeviceDetailRequest);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        if (queryDeviceDetailResponse == null || !queryDeviceDetailResponse.getBody().getSuccess()){
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        QueryDeviceDetailResponseBody.QueryDeviceDetailResponseBodyData data = queryDeviceDetailResponse.getBody().getData();
        DeviceVo deviceVo = deviceMapper.queryByIotId(deviceDto.getIotId());
        BeanUtil.copyProperties(data, deviceVo, CopyOptions.create().setIgnoreNullValue(true));
        return deviceVo;
    }

    @Override
    public void updateDevice(DeviceDto deviceDto) {
        deviceMapper.updateDevice(deviceDto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteDevice(DeviceDto deviceDto) {
        DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
        deleteDeviceRequest.setIotId(deviceDto.getIotId());
        deleteDeviceRequest.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        try {
            client.deleteDevice(deleteDeviceRequest);
        }catch (Exception e){
            e.printStackTrace();
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
        deviceMapper.deleteDevice(deviceDto.getIotId());
    }

    @Override
    public Map<String, String> queryThingModelPublished(DeviceDto deviceDto) {
        if (StrUtil.isEmpty(deviceDto.getProductKey())){
            throw new BaseException(BasicEnum.PARAMETER_MISSING);
        }
        //1. 调用阿里云物联网平台查询物模型定义信息
        QueryThingModelPublishedRequest queryThingModelPublishedRequest = new QueryThingModelPublishedRequest();
        queryThingModelPublishedRequest.setProductKey(deviceDto.getProductKey());
        queryThingModelPublishedRequest.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        QueryThingModelPublishedResponse queryThingModelPublishedResponse = null;
        try {
            queryThingModelPublishedResponse = client.queryThingModelPublished(queryThingModelPublishedRequest);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
        }
        //2. 解析响应结果
        if (!queryThingModelPublishedResponse.getBody().getSuccess()){
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
        }
        String thingModel = queryThingModelPublishedResponse.getBody().getData().getThingModelJson();
        return Map.of("thingModelJson", thingModel);
    }

    @Override
    public Map<String, Object> queryDevicePropertyStatus(DeviceDto deviceDto) {
        if (StrUtil.isEmpty(deviceDto.getDeviceName())|| StrUtil.isEmpty(deviceDto.getProductKey())){
            throw new BaseException(BasicEnum.PARAMETER_MISSING);
        }
        QueryDevicePropertyStatusRequest queryDevicePropertyStatusRequest = new QueryDevicePropertyStatusRequest();
        queryDevicePropertyStatusRequest.setDeviceName(deviceDto.getDeviceName());
        queryDevicePropertyStatusRequest.setProductKey(deviceDto.getProductKey());
        queryDevicePropertyStatusRequest.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        QueryDevicePropertyStatusResponse queryDevicePropertyStatusResponse = null;
        try {
            queryDevicePropertyStatusResponse = client.queryDevicePropertyStatus(queryDevicePropertyStatusRequest);
        }catch (Exception e){
            e.printStackTrace();
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
        if (!queryDevicePropertyStatusResponse.getBody().getSuccess()){
            queryDevicePropertyStatusResponse.getBody().getErrorMessage();
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
        QueryDevicePropertyStatusResponseBody.QueryDevicePropertyStatusResponseBodyDataList list = queryDevicePropertyStatusResponse.getBody().getData().getList();
        return Map.of("list", list);
    }

    @Override
    public List<DeviceDataGraphVo> queryDeviceDataListByDay(String iotId, String functionId, Long startTime, Long endTime) {
        // 构建24小时集合
        List<DeviceDataGraphVo> dataGraphVoList = DeviceDataGraphVo.dayInstance(LocalDateTimeUtil.of(startTime));
        //查询指标上报数据
        List<DeviceDataGraphVo> deviceDataGraphVoList = deviceDataMapper.queryDeviceDataListByDay(iotId, functionId, LocalDateTimeUtil.of(startTime), LocalDateTimeUtil.of(endTime));
        // 将查询到指标数据转化为Map , 方便查找
        Map<String, Double> dataMap = deviceDataGraphVoList.stream().collect(Collectors.toMap(DeviceDataGraphVo::getDateTime, DeviceDataGraphVo::getDataValue));
        // 组装数据
        dataGraphVoList.forEach(deviceDataGraphVo -> {
            // 获取对应时间的指标数据
            Double value = dataMap.getOrDefault(deviceDataGraphVo.getDateTime(), 0.0d);
            deviceDataGraphVo.setDataValue(value);
        });
        return dataGraphVoList;
    }

    @Override
    public List<DeviceDataGraphVo> queryDeviceDataListByWeek(String iotId, String functionId, Long startTime, Long endTime) {
        // 构建一周集合
        List<DeviceDataGraphVo> dataGraphVoList = DeviceDataGraphVo.weekInstance(LocalDateTimeUtil.of(startTime));
        //查询指标上报数据
        List<DeviceDataGraphVo> deviceDataGraphVoList = deviceDataMapper.queryDeviceDataListByWeek(iotId, functionId, LocalDateTimeUtil.of(startTime), LocalDateTimeUtil.of(endTime));
        // 将查询到指标数据转化为Map , 方便查找
        Map<String, Double> dataMap = deviceDataGraphVoList.stream().collect(Collectors.toMap(DeviceDataGraphVo::getDateTime, DeviceDataGraphVo::getDataValue));
        // 组装数据
        dataGraphVoList.forEach(deviceDataGraphVo -> {
            // 获取对应时间的指标数据
            Double value = dataMap.getOrDefault(deviceDataGraphVo.getDateTime(), 0d);
            deviceDataGraphVo.setDataValue(value);
        });
        return dataGraphVoList;
    }
}
